﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DA;
using System.Collections;
using System.Text.RegularExpressions;
using Entities;


namespace BL
{
    public class DataManager
    {
        public Products GetProduct(int productId)
        {
            StoreDataModel model = new StoreDataModel();

            return model.Products.SingleOrDefault(x => x.ProductId == productId);
        }

        public List<Products> GetProducts()
        {
            StoreDataModel model = new StoreDataModel();

            return model.Products.ToList();
        }

        public bool EditProduct(int productId, string name)
        {
            try
            {
                StoreDataModel model = new StoreDataModel();

                Products product = model.Products.SingleOrDefault(x => x.ProductId == productId);
                product.Name = name;
                model.SaveChanges();
                model.AcceptAllChanges();
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool AddProduct(Products product)
        {
            try
            {
                using (StoreDataModel model = new StoreDataModel())
                {
                    model.Products.AddObject(product);
                    model.SaveChanges();
                    model.AcceptAllChanges();
                }
            }
            catch
            {
                return false;
            }
            return true;
        }

        public IEnumerable<Categories> GetCategories()
        {
            StoreDataModel model = new StoreDataModel();

            return model.Categories.ToList();
        }

        public Categories GetCategory(int categoryId)
        {
            StoreDataModel model = new StoreDataModel();
            return model.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
        }

        public bool EditCategory(int categoryId, string name)
        {
            try
            {
                StoreDataModel model = new StoreDataModel();

                Categories category = model.Categories.SingleOrDefault(x => x.CategoryId == categoryId);
                category.Name = name;

                return model.SaveChanges() > 0;
            }
            catch
            {
                return false;
            }
        }

        public bool AddCategory(Categories category)
        {
            try
            {
                StoreDataModel model = new StoreDataModel();
                model.Categories.AddObject(category);

                return model.SaveChanges() > 0;
            }
            catch
            {
                return false;
            }
        }

        public List<Products> GetLowProducts()
        {
            const int low = 5;
            StoreDataModel model = new StoreDataModel();
            return model.Products.Where(x => x.InStock < low).ToList();
        }

        public bool AddStockToProduct(int newStock, int productId)
        {
            using (StoreDataModel model = new StoreDataModel())
            {
                Products product = model.Products.SingleOrDefault(x => x.ProductId == productId);

                if (product == null)
                    return false;

                product.InStock += newStock;

                int numOfChangedObjects = model.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);

                return numOfChangedObjects > 0;
            }
        }

        public List<Products> GetMinPrice(int parm)
        {
            StoreDataModel model = new StoreDataModel();
            return model.Products.Where(x => x.ItemPrice > parm).ToList();
        }

        public List<Products> GetProductByUnit(int unitId)
        {
            StoreDataModel model = new StoreDataModel();
            return model.Products.Where(x => x.QuantityUnitId == unitId).ToList();
        }

        public List<Products> GetProductByUnit(QuantityUnits unit)
        {
            return GetProductByUnit(unit.QuantityUnitId);
        }

        public IEnumerable<Products> GetSaledProducts(DateTime fromDate, DateTime toDate)
        {
            using (StoreDataModel model = new StoreDataModel())
            {
                IEnumerable<Products> ProductsList =
                    from p in model.Products
                    from ps in p.Store_ProductSales
                    where ps.Sales.SaleDate >= fromDate && ps.Sales.SaleDate <= toDate
                    select p;

                return ProductsList.ToList();
            }
        }

        public List<Products> GetProductsByCategories(IEnumerable<int> categoryIds)
        {
            using (StoreDataModel model = new StoreDataModel())
            {
                List<Products> ProductsList =
                    (from p in model.Products
                     from ps in p.ProductCategories
                     where categoryIds.Contains(ps.CategoryId)
                     select p)
                     .ToList();

                return ProductsList;
            }
        }

        public List<CsvError> ImportFile(string fileContent)
        {
            List<CsvError> fileErrors = new List<CsvError>();
            List<Products> validProducts = new List<Products>();

            string[] lines = Regex.Split(fileContent, Environment.NewLine);

            for (int lineIndex = 1; lineIndex < lines.Length; lineIndex++)
            {
                string[] RowColumns = Regex.Split(lines[lineIndex], ",");

                RowColumns[0].Trim();
                RowColumns[1].Trim();
                RowColumns[2].Trim();
                RowColumns[3].Trim();

                List<CsvError> productErrors = ValidateProduct(product, lineIndex);


                if (!productErrors.Any())
                {
                    Products product = new Products();
                    product.Name = RowColumns[0];
                    product.Description = RowColumns[1];
                    product.ItemPrice = Decimal.Parse(RowColumns[2]);
                    product.QuantityUnitId = int.Parse(RowColumns[3]);

                    validProducts.Add(product);
                }
                else
                {
                    fileErrors.AddRange(productErrors);
                }
            }

            using (StoreDataModel model = new StoreDataModel())
            {
                foreach (Products item in validProducts)
                {
                    model.AddToProducts(item);
                }

                model.SaveChanges();
            }

            return fileErrors;
        }

        public List<CsvError> ValidateProduct(Products product, int Line)
        {
            List<CsvError> errorsList = new List<CsvError>();

            if (String.IsNullOrEmpty(product.Name))
            {
                errorsList.Add(
                    new CsvError()
                    {
                        ErrorLine = Line,
                        ErrorDescription = "Product name is empty"
                    });
            }

            if (IsNameExist(product.Name))
            {
                errorsList.Add(
                    new CsvError()
                    {
                        ErrorLine = Line,
                        ErrorDescription = "Product name already exist in the database"
                    });
            }

            decimal temp;
            if (!Decimal.TryParse(product.ItemPrice.ToString(), out temp))
            {
                errorsList.Add(
                    new CsvError()
                    {
                        ErrorLine = Line,
                        ErrorDescription = "Product item price is not a valid value"
                    });
            }

            int temp2;
            if (!int.TryParse(product.QuantityUnitId.ToString(), out temp2))
            {
                errorsList.Add(
                    new CsvError()
                    {
                        ErrorLine = Line,
                        ErrorDescription = "Product item price is not a valid value"
                    });
            }
            try
            {
                product.QuantityUnitId = int.Parse(product.QuantityUnitId.ToString());
            }
            catch
            {
                errorsList.Add(
                    new CsvError()
                    {
                        ErrorLine = Line,
                        ErrorDescription = "Product Quntity id not exist in the database"
                    });
            }

            return errorsList;
        }

        public bool IsNameExist(string name)
        {
            using (StoreDataModel model = new StoreDataModel())
            {
                return model.Products.Any(x => x.Name == name);
            }
        }
    }
}
